package org.zakariya.flyoutmenu;

import ohos.aafwk.ability.fraction.Fraction;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.*;
import ohos.agp.utils.*;

import ohos.agp.window.dialog.CommonDialog;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.miscservices.timeutility.Time;
import ohos.multimodalinput.event.TouchEvent;

import java.time.chrono.HijrahChronology;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class FlyoutMenuView extends Component implements AnimatorValue.ValueUpdateListener, Component.DrawTask, Component.TouchEventListener {
    double testProgress = 0;

    @Override
    public void onUpdate(AnimatorValue animatorValue, float v) {
        if (animatorValue == menuAnimator) {
            testProgress = v;
            menuOpenTransition = Math.abs((double) v - 1); //
            if (null != menuOverlayView) {
                menuOverlayView.setVisibility(VISIBLE);
            }
        } else if (animatorValue == selectionAnimator) {
            selectionTransition = v;
        }
        if (menuOverlayView != null) {
            menuOverlayView.invalidate();
        }
        if(menuPosition.equals("top")) {
            invalidate();
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        final float pinion = 0.25f;
        if (menuOpenTransition < pinion) {
            drawButton(canvas, 1 - menuOpenTransition / pinion);
        }
    }

    /**
     * FlyoutMenu的触摸事件
     */
    EventHandler eventHandler;
    /**
     * 按下时间
     */
    private long downTime = 0;
    /**
     * 抬起时间
     */
    private long upTime = 0;
    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        compact.correctY(touchEvent);
        double x = touchEvent.getPointerScreenPosition(0).getX();
        double y = touchEvent.getPointerScreenPosition(0).getY();
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                if (isInDialogMode()) {
                    menuOverlayViewAttached = false;
                    animateMenuOpenChange(true, false);  //dianji
                } else {
                    downTime = Time.getCurrentTime();
                    if (menuAnimator != null) {
                        menuAnimator.start();
                    }
                    eventHandler = new EventHandler(EventRunner.getMainEventRunner());
                    eventHandler.postTask(() -> {
                        animateMenuOpenChange(true, false);  //dianji
                    }, 250);
                }
                wasOpenedAsDialog = false;
                break;

            case TouchEvent.PRIMARY_POINT_UP:
                if (!isInDialogMode()) {
                    upTime = Time.getCurrentTime();
                    if (upTime - downTime < 250) {
                        if (eventHandler != null)
                            eventHandler.removeAllEvent();
                        return true;
                    }
                }
                // if we're configured to behave in dialog mode, mark that we were opened in dialog
                // mode IFF user release touch on top of the button. this will signal to MenuOverlayView
                // to handle ACTION_DOWN & ACTION_UP events
                wasOpenedAsDialog = true;
                if (isInDialogMode()) {
                    return true;
                }

                if (menuPosition.equals("top")) {
                    MenuItem item = null;
                    if (menuOverlayView != null) {
                        if (menuOverlayView.findMenuItemAtLocalPosition((float) (x - translatex), (float)(y - 176 - translatey)) != null) {  //176  状态栏的高度
                            setSelectedMenuItem(menuOverlayView.findMenuItemAtLocalPosition((float) (x - translatex), (float) (y - 176 - translatey)));
                        } else {
                            detachMenuOverlayView();
                            return true;
                        }
                    }
//				if(eventHandler != null) {
//					eventHandler.removeAllEvent();
//				}
                    detachMenuOverlayView();
                }
//				dismissMenuWithMenuItem();

                break;
        }
        return true;
    }


    public interface SelectionListener {
        void onItemSelected(FlyoutMenuView flyoutMenuView, MenuItem item);

        void onDismissWithoutSelection(FlyoutMenuView flyoutMenuView);
    }

    @SuppressWarnings("unused")
    public static class Size {
        int width;
        int height;

        public Size() {
        }

        public Size(int width, int height) {
            this.width = width;
            this.height = height;
        }

        public int getWidth() {
            return width;
        }

        public void setWidth(int width) {
            this.width = width;
        }

        public int getHeight() {
            return height;
        }

        public void setHeight(int height) {
            this.height = height;
        }

        @Override
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            }

            if (o instanceof Size) {
                Size other = (Size) o;
                return other.width == width && other.height == height;
            }

            return false;
        }

        @Override
        public int hashCode() {
            int result = 17;
            result = 31 * result + width;
            result = 31 * result + height;
            return result;
        }
    }

    public static abstract class ButtonRenderer {

        Paint paint;

        public ButtonRenderer() {
            paint = new Paint();
            paint.setAntiAlias(true);
        }

        public void onDrawButtonBase(Canvas canvas, RectFloat buttonBounds, Color buttonColor, float alpha) {  //  int buttonColor转换为Color
            paint.setAlpha((int) (alpha * 255f));
            paint.setColor(buttonColor);
            paint.setStyle(Paint.Style.FILL_STYLE);
//			canvas.drawOval(buttonBounds, paint);
            canvas.drawCircle(buttonBounds.getCenter().getPointX(), buttonBounds.getCenter().getPointY(), 100, paint);
//			canvas.drawCircle(buttonBounds.getCenter().getPointX(),buttonBounds.getCenter().getPointY(),10,paint);
        }

        /**
         * 绘制圆形按钮的内容
         *
         * @param canvas       Canvas draw
         * @param buttonBounds Rect bounds
         * @param buttonColor  the color value
         * @param alpha        the alpha
         */
        abstract public void onDrawButtonContent(Canvas canvas, RectFloat buttonBounds, Color buttonColor, float alpha);
    }

    /**
     * Base class for layout managers which position MenuItem instances in the FlyoutMenu.
     * Layout is responsible for determining the minimum size menu that can show all items, and
     * is responsible for positioning items individually.
     */
    public interface Layout {
        /**
         * Get the size of items in the menu
         *
         * @param itemCount    the number of items in the menu
         * @param itemWidthPx  width of item to layout
         * @param itemHeightPx height of the item to layout
         * @param itemMarginPx the margin around the item
         * @return the minimum size the FlyoutMenu must be to display all items. How they're packed is up to the Layout
         */
        Size getMinimumSizeForItems(int itemCount, int itemWidthPx, int itemHeightPx, int itemMarginPx);

        /**
         * Get the layout of items in the menu
         *
         * @param positionInList the individual MenuItem's index in the adapter
         * @param itemWidthPx    width of item to layout
         * @param itemHeightPx   height of the item to layout
         * @param itemMarginPx   the margin around the item
         * @return the Rect describing the position of this item, in pixels, where the origin (0,0) is the top left of the flyout menu
         */
        RectFloat getLayoutRectForItem(int positionInList, int itemWidthPx, int itemHeightPx, int itemMarginPx);
    }

    /**
     * Basic Layout implementation that places items in a grid.
     */
    @SuppressWarnings("unused")
    public static class GridLayout implements Layout {

        public static final int UNSPECIFIED = 0;

        int cols, rows;

        /**
         * Creates a GirdLayout with a specified number of columns or rows. You must specify one concrete value, and
         * one unspecified using GridLayout.UNSPECIFIED. E.g. calling GridLayout(4, GridLayout.UNSPECIFIED) would produce
         * a layout with 4 columns. If your adapter described 12 items, the layout would have three rows.
         *
         * @param cols number of columns to use, or GridLayout.UNSPECIFIED
         * @param rows number of rows to use, or GridLayout.UNSPECIFIED
         * @throws IllegalArgumentException one of cols or rows attribute must be 0
         */
        public GridLayout(int cols, int rows) {
            this.cols = cols;
            this.rows = rows;

            if (this.cols > 0 && this.rows > 0) {
                throw new IllegalArgumentException("one of cols or rows attribute must be 0, both cannot be set");
            }
        }

        @Override
        public Size getMinimumSizeForItems(int itemCount, int itemWidthPx, int itemHeightPx, int itemMarginPx) {
            Size size = new Size();
            if (cols > 0) {
                // fixed number of columns
                int requiredRows = (int) Math.ceil((float) itemCount / (float) cols);
                size.width = cols * itemWidthPx + ((cols + 1) * itemMarginPx);
                size.height = requiredRows * itemHeightPx + ((requiredRows + 1) * itemMarginPx);
            } else if (rows > 0) {
                int requiredCols = (int) Math.ceil((float) itemCount / (float) rows);
                size.width = requiredCols * itemWidthPx + ((requiredCols + 1) * itemMarginPx);
                size.height = rows * itemHeightPx + ((rows + 1) * itemMarginPx);
            } else {
                throw new IllegalArgumentException("one of cols or rows attribute must be 0, both cannot be set");
            }
            return size;
        }

        @Override
        public RectFloat getLayoutRectForItem(int positionInList, int itemWidthPx, int itemHeightPx, int itemMarginPx) {
            int row;
            int col;

            if (cols > 0) { //2
                row = (int) Math.floor((float) positionInList / cols);//0
                col = positionInList - row * cols;//0
            } else if (rows > 0) {
                col = (int) Math.floor((float) positionInList / rows);
                row = positionInList - col * rows;
            } else {
                throw new IllegalArgumentException("one of cols or rows attribute must be 0, both cannot be set");
            }

            RectFloat rect = new RectFloat();
            rect.left = col * itemWidthPx + (col + 1) * itemMarginPx;
            rect.top = row * itemHeightPx + (row + 1) * itemMarginPx;
            rect.right = rect.left + itemWidthPx;
            rect.bottom = rect.top + itemHeightPx;
            return rect;
        }
    }

    /**
     * Base class for a FlyoutMenu's data source - the thing providing the MenuItems
     */
    public interface Adapter {
        /**
         * 获取adapter数量
         *
         * @return the number of MenuItems in this Adapter
         */
        int getCount();

        /**
         * Get item by position
         *
         * @param position the index of the item to vend
         * @return the MenuItem at position
         */
        MenuItem getItem(int position);
    }

    /**
     * Convenience Adapter implementation wrapping an Array.
     *
     * @param <T>
     */
    @SuppressWarnings("unused")
    public static class ArrayAdapter<T> implements Adapter {

        private List<T> items;

        public ArrayAdapter(List<T> items) {
            this.items = items;
        }

        public ArrayAdapter(T[] items) {
            this.items = Arrays.asList(items);
        }

        @Override
        public int getCount() {
            return items.size();
        }

        @Override
        public MenuItem getItem(int position) {
            return (MenuItem) items.get(position);
        }
    }


    @SuppressWarnings("unused")
    private static final String TAG = FlyoutMenuView.class.getSimpleName();

    private static final int ANIMATION_DURATION_MILLIS = 225; // 225 normal

    private static final int DEFAULT_BUTTON_ELEVATION_DP = 4;
    private static final int DEFAULT_MENU_ELEVATION_DP = 8;

    private static final int MENU_CORNER_RADIUS_DP = 4;
    private static final int DEFAULT_ITEM_SIZE_DP = 48;
    private static final int DEFAULT_ITEM_MARGIN_DP = 8;

    private static final int DEFAULT_BUTTON_SIZE_DP = 56;

    private static final float DEFAULT_HORIZONTAL_MENU_ANCHOR = 1f;
    private static final boolean DEFAULT_HORIZONTAL_MENU_ANCHOR_OUTSIDE = false;
    private static final float DEFAULT_VERTICAL_MENU_ANCHOR = 0.5f;
    private static final boolean DEFAULT_VERTICAL_MENU_ANCHOR_OUTSIDE = false;
    private static final float DEFAULT_MENU_MARGIN_DP = 16;

    private static final int SHADOW_COLOR = 0xFF000000;
    private static final int SHADOW_ALPHA = 32;


    Paint paint;


    int buttonBackgroundColor = 0xFFFFFFFF;


    int menuBackgroundColor = 0xFFFFFFFF;


    int selectedItemBackgroundColor = 0x0; // defaults to transparent


    int shieldColor = 0x77303030;

    boolean shieldVisible;

    float buttonElevation;
    float menuElevation;

    int buttonSize;
    Point buttonCenter;
    RectFloat buttonFillOval = new RectFloat();
    int buttonRadius;

    Element buttonDrawable;  //Drawable  转换为Element
    PixelMap buttonShadowBitmap;
    Point centerPoint;

    float horizontalMenuAnchor = 0.5f;
    float verticalMenuAnchor = 0.5f;
    boolean horizontalMenuAnchorOutside = false;
    boolean verticalMenuAnchorOutside = false;
    float menuMargin = 0;

    int itemWidth;
    int itemHeight;
    int itemMargin;
    Adapter adapter;
    Layout layout;
    MenuItem selectedMenuItem;
    MenuItem previouslySelectedMenuItem;
    List<MenuItem> list = new ArrayList<>();
    RectFloat selectedMenuItemBounds = new RectFloat();

    SelectionListener selectionListener;
    ButtonRenderer buttonRenderer;

    AnimatorValue menuAnimator;
    AnimatorValue selectionAnimator;
    double menuOpenTransition; // 0 is closed, 1 is menuOpen
    double selectionTransition;

    boolean menuOverlayViewAttached = false;
    MenuOverlayView menuOverlayView;  //查看具体实现
//	CustomGridView menuOverlayView;

    boolean dialogMode = false;
    boolean wasOpenedAsDialog = false;
    private TouchEventCompact compact;

    String menuPosition = "bottom";
    String buttonColor = "";

    public FlyoutMenuView(Context context) {
        super(context);
        init(null, 0);
    }

    public FlyoutMenuView(Context context, AttrSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public FlyoutMenuView(Context context, AttrSet attrs, int defStyle) {
        super(context, attrs);
        init(attrs, defStyle);
    }

    private void init(AttrSet attrs, int defStyle) {

        // workaround for lack of clip path in API < 18
//		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
//			setLayerType(LAYER_TYPE_SOFTWARE, null);
//		}
        PxUtil.initContext(getContext());
        compact = new TouchEventCompact();
        paint = new Paint();
        paint.setAntiAlias(true);

        // But where's the ALPHA coming from? colorBackground is opaque...


        // Load attributes
        //colorOn = a.getColor(R.styleable.app_color_on, DEFAULT_COLOR_ON);
        //colorOn = AttrUtils.getColor(attrs, "colorOn", DEFAULT_COLOR_ON);
//		final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FlyoutMenuView, defStyle, 0);
        setButtonSize(AttrUtils.getInteger(attrs, "fmButtonSize", (int) dp2px(DEFAULT_BUTTON_SIZE_DP)));//(int)dp2px(DEFAULT_BUTTON_SIZE_DP));
        setDialogMode(AttrUtils.getBoolean(attrs, "fmDialogMode", false));
        setButtonBackgroundColor(AttrUtils.getInteger(attrs, "fmButtonBackgroundColor", buttonBackgroundColor));//buttonBackgroundColor);
        setMenuBackgroundColor(AttrUtils.getInteger(attrs, "fmMenuBackgroundColor", menuBackgroundColor));//menuBackgroundColor);
        setSelectedItemBackgroundColor(AttrUtils.getInteger(attrs, "fmSelectedItemBackgroundColor", selectedItemBackgroundColor));//selectedItemBackgroundColor);
        buttonColor = AttrUtils.getString(attrs, "fmSelectedItemBackgroundColor", selectedItemBackgroundColor + "");
        setShieldVisible(AttrUtils.getBoolean(attrs, "fmShieldVisible", false));//false);
        setShieldColor(AttrUtils.getInteger(attrs, "fmShieldColor", shieldColor));//shieldColor); //fmShieldColor
//		itemWidth = AttrUtils.getInteger(attrs,"fmMenuWidth",(int)dp2px(DEFAULT_ITEM_SIZE_DP));
        setItemWidth(AttrUtils.getInteger(attrs, "fmItemWidth", (int) dp2px(DEFAULT_ITEM_SIZE_DP)));//(int) dp2px(DEFAULT_ITEM_SIZE_DP));
        setItemHeight(AttrUtils.getInteger(attrs, "fmItemHeight", (int) dp2px(DEFAULT_ITEM_SIZE_DP)));//(int) dp2px(DEFAULT_ITEM_SIZE_DP));
        setItemMargin(AttrUtils.getInteger(attrs, "fmItemMargin", 26));//(int) dp2px(DEFAULT_ITEM_MARGIN_DP));

        setMenuMargin(AttrUtils.getInteger(attrs, "fmMenuMargin", (int) dp2px(DEFAULT_MENU_MARGIN_DP)));//(int) dp2px(DEFAULT_MENU_MARGIN_DP));
        setHorizontalMenuAnchor(AttrUtils.getFloat(attrs, "fmHorizontalMenuAnchor", DEFAULT_HORIZONTAL_MENU_ANCHOR));//DEFAULT_HORIZONTAL_MENU_ANCHOR);
        setHorizontalMenuAnchorOutside(AttrUtils.getBoolean(attrs, "fmHorizontalMenuAnchorOutside", DEFAULT_HORIZONTAL_MENU_ANCHOR_OUTSIDE));//DEFAULT_HORIZONTAL_MENU_ANCHOR_OUTSIDE);
        setVerticalMenuAnchor(AttrUtils.getFloat(attrs, "fmVerticalMenuAnchor", DEFAULT_VERTICAL_MENU_ANCHOR));//DEFAULT_VERTICAL_MENU_ANCHOR);
        setVerticalMenuAnchorOutside(AttrUtils.getBoolean(attrs, "fmVerticalMenuAnchorOutside", DEFAULT_VERTICAL_MENU_ANCHOR_OUTSIDE));//DEFAULT_VERTICAL_MENU_ANCHOR_OUTSIDE);


        // if a menuAnchor is defined, it will override explicit menu anchors read above
        parseMenuAnchorSpec(AttrUtils.getString(attrs, "fmMenuAnchor", "top"));

        menuPosition = AttrUtils.getString(attrs, "fmMenuAnchor", "top");
//		parseMenuAnchorSpec(a.getString(R.styleable.FlyoutMenuView_fmMenuAnchor));

        setButtonElevation((int) dp2px(DEFAULT_BUTTON_ELEVATION_DP));
        setMenuElevation((int) dp2px(DEFAULT_MENU_ELEVATION_DP));
//		setButtonDrawable(a.getDrawable(R.styleable.FlyoutMenuView_fmButtonSrc));


//		setButtonDrawable(a.getDrawable(R.styleable.FlyoutMenuView_fmButtonSrc));  暂未找到替换的
        updateLayoutInfo();
        addDrawTask(this);
        setTouchEventListener(this);
//		setEstimateSizeListener(this);
        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {
//				updateLayoutInfo();

                leftPosition = getComponentPosition().left;
                bottomPosition = getComponentPosition().bottom;
                topPosition = getComponentPosition().top;
            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {

            }
        });

        menuAnimator = new AnimatorValue();
        menuAnimator.setDuration(400);
        menuAnimator.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
        menuAnimator.setValueUpdateListener(this);
    }

    private int leftPosition = 0;
    private int bottomPosition = 0;
    private int topPosition = 0;

    @Override
    public void addDrawTask(DrawTask task) {
        super.addDrawTask(task);
        onDraw(this, mCanvasForTaskOverContent);
    }


    public List<FlyoutMenuView.MenuItem> setData(List<MenuItem> list) {
        this.list = list;
        return this.list;
    }

    @SuppressWarnings("unused")
    public Adapter getAdapter() {
        return adapter;
    }

    @SuppressWarnings("unused")
    public void setAdapter(Adapter adapter) {
        this.adapter = adapter;

        for (int i = 0; i < adapter.getCount(); i++) {
            list.add(adapter.getItem(i));
        }
    }

    public Layout getLayout() {
        return layout;
    }

    public void setLayout(Layout layout) {
        this.layout = layout;

        if (menuOverlayView != null) {
//			menuOverlayView.invalidateMenuItemLayout();
        }
    }

    void drawButton(Canvas canvas, double alpha) {  //需要研究这个方法，是怎么绘制内容的

        // scale button down as it fades out
        if (alpha < 1) {
            Matrix m = new Matrix();
            m.preTranslate(-buttonCenter.getPointX(), -buttonCenter.getPointY());
            m.postScale((float) alpha, (float) alpha);
            m.postTranslate(buttonCenter.getPointX(), buttonCenter.getPointY());
            canvas.concat(m);
        }

//        if (buttonElevation > 0) {  //绘制图
//            if (buttonShadowBitmap == null) {
//                buttonShadowBitmap = createButtonShadowBitmap();
//            }
//
//            paint.setAlpha(1);//(int)(alpha * alpha * alpha) * 255)
//            float buttonShadowOffset = buttonElevation / 2;
//            canvas.drawPixelMapHolder(new PixelMapHolder(buttonShadowBitmap), buttonCenter.getPointX() - buttonShadowBitmap.getImageInfo().size.width / 2, buttonCenter.getPointY() - buttonShadowBitmap.getImageInfo().size.height / 2 + buttonShadowOffset, paint);// );
//        }
        int scaledAlpha = (int) (alpha * 255);
        paint.setAlpha(scaledAlpha);//scaledAlpha);

        if (buttonRenderer == null) {  //绘制圆
            paint.setColor(Color.RED);//new Color(buttonBackgroundColor));//0xFFFFFFFF
            canvas.drawOval(buttonFillOval, paint);
        }

        if (buttonDrawable != null) {
            buttonDrawable.setAlpha(scaledAlpha);

            // scale the radius to fit drawable inside circle
            double innerRadius = buttonRadius / 1.41421356237f;
            buttonDrawable.setBounds(
                    (int) ((double)buttonCenter.getPointX() - innerRadius),
                    (int) ((double)buttonCenter.getPointY() - innerRadius),
                    (int) ((double)buttonCenter.getPointX() + innerRadius),
                    (int) ((double)buttonCenter.getPointY() + innerRadius));

            buttonDrawable.drawToCanvas(canvas);//圆缩放
        } else if (buttonRenderer != null) {
            buttonRenderer.onDrawButtonBase(canvas, buttonFillOval, new Color(buttonBackgroundColor), (float) alpha);
            buttonRenderer.onDrawButtonContent(canvas, buttonFillOval, new Color(buttonBackgroundColor), (float) alpha);
            centerPoint = new Point(buttonFillOval.getCenter().getPointX(), buttonFillOval.getCenter().getPointX());
        }
    }

    /**
     * Ability or Fraction may want to dismiss a FlyoutMenu on back button press. If the menu is open,
     * this will dismiss it and return true. If the menu was not open, this will perform no action and will return false.
     *
     * @return dismisses the menu, returning true if the menu was open, false if not.
     */
    public boolean dismiss() {

        if (menuOverlayView != null) {
            animateMenuOpenChange(false, false);
            return true;
        }

        return false;
    }

    /**
     * 关闭显示的menu
     */
    void dismissMenuWithMenuItem() {
//		if (item != null) {
//			setSelectedMenuItem(item);
//		} else if (selectionListener != null) {
//			selectionListener.onDismissWithoutSelection(this);
//		}

        // close menu - delay iff an item was selected
        animateMenuOpenChange(false, true);
    }

    /**
     * 显示menu的内容
     *
     * @param open  是否展开menu
     * @param delay  延迟
     */
    boolean startShow = false;

    void animateMenuOpenChange(final boolean open, boolean delay) {
        startShow = open;
        if (open) {
            attachMenuOverlayView();
        } else {
            detachMenuOverlayView();
        }
        if (menuAnimator != null) {
            menuAnimator.cancel();
        }


        menuAnimator.start();
//		menuAnimator.setStartDelay(delay ? ANIMATION_DURATION_MILLIS : 0);
	/*	menuAnimator.setStateChangedListener(new Animator.StateChangedListener() {
			boolean canceled = false;
			@Override
			public void onStart(Animator animator) {
				if (open) {
//					attachMenuOverlayView();
				}

			}

			@Override
			public void onStop(Animator animator) {
				detachMenuOverlayView();
			}

			@Override
			public void onCancel(Animator animator) {
				canceled = true;
			}

			@Override
			public void onEnd(Animator animator) {
//				if (!open && !canceled) {
//					detachMenuOverlayView();
//				}
			}

			@Override
			public void onPause(Animator animator) {

			}

			@Override
			public void onResume(Animator animator) {

			}
		});*/
    }


    /**
     * Get the button Element
     *
     * @return the drawable rendered by the button
     */
    @SuppressWarnings("unused")
    public Element getButtonDrawable() {
        return buttonDrawable;
    }

    @SuppressWarnings("unused")
    public ButtonRenderer getButtonRenderer() {
        return buttonRenderer;
    }

    /**
     * Set ButtonRenderer
     *
     * @param buttonRenderer 按钮内容的类
     */
    @SuppressWarnings("unused")
    public void setButtonRenderer(ButtonRenderer buttonRenderer) {
        this.buttonRenderer = buttonRenderer;
        this.buttonDrawable = null;
    }

    /**
     * Set the drawable drawn by the button
     *
     * @param buttonDrawable the thing to draw in the button
     */
    public void setButtonDrawable(Element buttonDrawable) {
        this.buttonDrawable = buttonDrawable;
        this.buttonRenderer = null;
        invalidate();
    }

    /**
     * Set a bitmap to use as image drawn by button
     *
     * @param bitmap the bitmap to draw in the button
     */
    @SuppressWarnings("unused")
    public void setButtonImage(PixelMap bitmap) {
        setButtonDrawable(new PixelMapElement(bitmap));
    }

    /**
     * Get item width in pixels
     *
     * @return the width in pixels of items in the menu
     */
    @SuppressWarnings("unused")
    public int getItemWidth() {
        return itemWidth;
    }

    /**
     * Set the width in pixels of items in the menu
     *
     * @param itemWidth the width in pixels of items in the menu
     */
    public void setItemWidth(int itemWidth) {
        this.itemWidth = itemWidth;
    }

    /**
     * Get item height in pixels
     *
     * @return the height in pixels of items in the menu
     */
    @SuppressWarnings("unused")
    public int getItemHeight() {
        return itemHeight;
    }

    /**
     * Set the height in pixels of items in the menu
     *
     * @param itemHeight the height in pixels of items in the menu
     */
    public void setItemHeight(int itemHeight) {
        this.itemHeight = itemHeight;
    }

    /**
     * Get item margin in pixels
     *
     * @return the margin in pixels around items in the menu
     */
    @SuppressWarnings("unused")
    public int getItemMargin() {
        return itemMargin;
    }

    /**
     * Set the margin in pixels around items in the menu
     *
     * @param itemMargin the margin in pixels around items in the menu
     */
    public void setItemMargin(int itemMargin) {
        this.itemMargin = itemMargin;
    }

    /**
     * Get the menu color
     *
     * @return the argb color of the background fill of the menu
     */
    @SuppressWarnings("unused")
    public int getMenuBackgroundColor() {
        return menuBackgroundColor;
    }

    /**
     * Set the background argb color of the menu
     *
     * @param menuBackgroundColor the argb color of the background of the menu
     */
    public void setMenuBackgroundColor(int menuBackgroundColor) {
        this.menuBackgroundColor = ColorUtils.setAlphaComponent(menuBackgroundColor, 255);
        if (menuOverlayView != null) {
            menuOverlayView.invalidate();
        }
    }

    @SuppressWarnings("unused")
    public int getShieldColor() {
        return shieldColor;
    }

    public void setShieldColor(int shieldColor) {
        this.shieldColor = shieldColor;
        if (menuOverlayView != null) {
            menuOverlayView.invalidate();
        }
    }

    public boolean isShieldVisible() {
        return shieldVisible;
    }

    public void setShieldVisible(boolean shieldVisible) {
        this.shieldVisible = shieldVisible;
        if (menuOverlayView != null) {
            menuOverlayView.invalidate();
        }
    }

    /**
     * Get the  background for the button
     *
     * @return Get the background fill color for the button
     */
    @SuppressWarnings("unused")
    public int getButtonBackgroundColor() {
        return buttonBackgroundColor;
    }

    /**
     * Set the background fill color for the button
     *
     * @param buttonBackgroundColor the argb color for the background of the button
     */
    public void setButtonBackgroundColor(int buttonBackgroundColor) {
        this.buttonBackgroundColor = ColorUtils.setAlphaComponent(buttonBackgroundColor, 255);
        invalidate();
    }

    /**
     * Get the color used to highlight the selected menu item
     *
     * @return the color used to highlight the selected menu item
     */
    @SuppressWarnings("unused")
    public int getSelectedItemBackgroundColor() {
        return selectedItemBackgroundColor;
    }

    /**
     * Set the color used to highlight the selected menu item
     *
     * @param selectedItemBackgroundColor the argb color used to highlight selection
     */
    public void setSelectedItemBackgroundColor(int selectedItemBackgroundColor) {
        this.selectedItemBackgroundColor = selectedItemBackgroundColor;
        if (menuOverlayView != null) {
            menuOverlayView.invalidate();
        }
    }


    /**
     * Get  the horizontal anchor point of the menu.
     *
     * @return the horizontal anchor point of the menu.
     */
    @SuppressWarnings("unused")
    public float getHorizontalMenuAnchor() {
        return horizontalMenuAnchor;
    }

    /**
     * Set the horizontal anchorpoint of the menu. A value of 0 anchors the menu
     * to the left of the button, and a value of 1 anchors to the right. A value of 0.5
     * centers the menu horizontally.
     *
     * @param horizontalMenuAnchor the anchor value, from 0 to 1
     */
    public void setHorizontalMenuAnchor(float horizontalMenuAnchor) {
        this.horizontalMenuAnchor = Math.min(Math.max(horizontalMenuAnchor, 0), 1);

        if (menuOverlayView != null) {
//			menuOverlayView.invalidateMenuFill();
        }
    }

    /**
     * Get the vertical anchor point of the menu.
     *
     * @return the vertical anchor point of the menu.
     */
    @SuppressWarnings("unused")
    public float getVerticalMenuAnchor() {
        return verticalMenuAnchor;
    }

    /**
     * Set the vertical anchorpoint of the menu. A value of 0 anchors the menu
     * to the top of the button, and a value of 1 anchors to the bottom. A value of 0.5
     * centers the menu vertically.
     *
     * @param verticalMenuAnchor the anchor value, from 0 to 1
     */
    public void setVerticalMenuAnchor(float verticalMenuAnchor) {
        this.verticalMenuAnchor = Math.min(Math.max(verticalMenuAnchor, 0), 1);

        if (menuOverlayView != null) {
//			menuOverlayView.invalidateMenuFill();
        }
    }

    /**
     * whether the horizontal anchor is out side.
     *
     * @return if true, the horizontal anchor point attaches to the left edge of the button when horizontal anchor is 0, and to the right edge when horizontal anchor is 1
     */
    @SuppressWarnings("unused")
    public boolean isHorizontalMenuAnchorOutside() {
        return horizontalMenuAnchorOutside;
    }

    /**
     * Get the selection listener
     *
     * @return get the SelectionListener instance
     */
    @SuppressWarnings("unused")
    public SelectionListener getSelectionListener() {
        return selectionListener;
    }

    /**
     * Set a listener to be notified when items in the menu are selected
     *
     * @param selectionListener listener to be notified on item selection
     */
    @SuppressWarnings("unused")
    public void setSelectionListener(SelectionListener selectionListener) {
        this.selectionListener = selectionListener;
    }

    /**
     * Set horizontal anchor
     *
     * @param horizontalMenuAnchorOutside if true, a horizontal anchor of 0 will hang the menu's right edge off the left edge of the button, and a value of 1 will hang the menu's left edge off the right edge of the button. If false, and the horizontal anchor is 0, the menu's left edge will hang off the button's right edge, and if the horizontal anchor is 1, the menu's right edge will anchor to the button's left
     */
    public void setHorizontalMenuAnchorOutside(boolean horizontalMenuAnchorOutside) {
        this.horizontalMenuAnchorOutside = horizontalMenuAnchorOutside;

        if (menuOverlayView != null) {
//			menuOverlayView.invalidateMenuFill();
        }
    }

    /**
     * whether the vertical anchor is out side.
     *
     * @return if true, the vertical anchor point attaches to the top edge of the button when vertical anchor is 0, and to the bottom edge when vertical anchor is 1
     */
    @SuppressWarnings("unused")
    public boolean isVerticalMenuAnchorOutside() {
        return verticalMenuAnchorOutside;
    }

    /**
     * Set vertical anchor whether outside
     *
     * @param verticalMenuAnchorOutside if true, a vertical anchor of 0 will hang the menu's bottom edge off the top edge of the button, and a value of 1 will hang the menu's top edge off the bottom edge of the button. If false, and the vertical anchor is 0, the menu's bottom edge will hang off the button's bottom edge, and if the vertical anchor is 1, the menu's top edge will anchor to the button's top edge
     */
    public void setVerticalMenuAnchorOutside(boolean verticalMenuAnchorOutside) {
        this.verticalMenuAnchorOutside = verticalMenuAnchorOutside;
    }

    /**
     * Get the margin outside the menu. This margin will be taken into account when the layout of the menu tries to
     * prevent the menu from going off screen or overlaying the navigation bar
     *
     * @return the margin in pixels outside the menu
     */
    @SuppressWarnings("unused")
    public float getMenuMargin() {
        return menuMargin;
    }

    /**
     * Set the margin outside the menu. This margin will be taken into account when the layout of the menu tries to
     * prevent the menu from going off screen or overlaying the navigation bar
     *
     * @param menuMargin the margin in pixels outside the menu
     */
    public void setMenuMargin(float menuMargin) {
        this.menuMargin = menuMargin;
    }

    @SuppressWarnings("unused")
    public float getButtonElevation() {
        return buttonElevation;
    }

    /**
     * Set the button element's elevation in pixels
     *
     * @param buttonElevation the button element's elevation in pixels. Set to zero to disable elevation shadow.
     */
    public void setButtonElevation(float buttonElevation) {
        this.buttonElevation = buttonElevation;
        buttonShadowBitmap = null; // invalidate
    }

    @SuppressWarnings("unused")
    public float getMenuElevation() {
        return menuElevation;
    }

    /**
     * Set the menu element's elevation in pixels
     *
     * @param menuElevation the menu element's elevation in pixels. Set to zero to disable elevation shadow.
     */
    public void setMenuElevation(float menuElevation) {
        this.menuElevation = menuElevation;
        if (this.menuOverlayView != null) {
//			this.menuOverlayView.menuShadowBitmap = null;
        }
    }

    /**
     * get the currently selected menu item
     *
     * @return get the currently selected menu item, or null if none is selected
     */
    @SuppressWarnings("unused")
    public MenuItem getSelectedMenuItem() {
        return selectedMenuItem;
    }

    /**
     * Set the current menu item selection. Triggers notification of SelectionListener, if one assigned
     *
     * @param selectedMenuItem MenuItem to make the current selection
     */
    public void setSelectedMenuItem(MenuItem selectedMenuItem) {
        if (selectionListener != null && selectedMenuItem != null) {
            selectionListener.onItemSelected(this, selectedMenuItem);
            if (menuOverlayView != null) {
                menuOverlayView.invalidate();
            }
        }

        if (selectedMenuItem != this.selectedMenuItem) {
            this.selectedMenuItem = selectedMenuItem;
            invalidate();
        }
    }

    /**
     * Set the current selection to the menu item at a given adapter position
     *
     * @param adapterPosition adapter position of menu item to make the current selection
     */
    @SuppressWarnings("unused")
    public void setSelectedMenuItemByAdapterPosition(int adapterPosition) {
        setSelectedMenuItem(adapter.getItem(adapterPosition));
    }

    /**
     * Set the current selection to the menu item with a given ID
     *
     * @param menuItemId id of the menu item to make the current selection
     */
    @SuppressWarnings("unused")
    public void setSelectedMenuItemById(int menuItemId) {
        for (int i = 0, n = adapter.getCount(); i < n; i++) {
            MenuItem item = adapter.getItem(i);
            if (item.getId() == menuItemId) {
                setSelectedMenuItem(item);
                return;
            }
        }
    }

    @SuppressWarnings("unused")
    public boolean isInDialogMode() {
        return dialogMode;
    }

    /**
     * FlyoutMenuView by default behaves as follows: press to open -> drag to desired item -> release to select. In dialog
     * mode, pressing opens the menu, releasing does nothing. A subsequent tap on an item selects it and closes the menu.
     *
     * @param dialogMode if true, the FlyoutMenuView will operate in dialog mode.
     */
    public void setDialogMode(boolean dialogMode) {
        this.dialogMode = dialogMode;
    }

    /**
     * Get the button size
     *
     * @return the size in pixels of the trigger button
     */
    public int getButtonSize() {
        return buttonSize;
    }

    /**
     * Set the button size
     *
     * @param buttonSize the size in pixels of the trigger button
     */
    public void setButtonSize(int buttonSize) {
        this.buttonSize = buttonSize;
        postLayout();
    }

    /**
     * 初始化绘制需要的高宽以及区域
     */
    void updateLayoutInfo() {
        double innerWidth = getWidth() - (getPaddingLeft() + getPaddingRight());
        double innerHeight = getHeight() - (getPaddingTop() + getPaddingBottom());
        buttonCenter = new Point((float) (getPaddingLeft() + (innerWidth / 2)), (float) (getPaddingTop() + (innerHeight / 2)));
        buttonRadius = (int) Math.min(innerWidth / 2, innerHeight / 2);
        final RectFloat buttonFillOval = new RectFloat(
                (float) ((double)buttonCenter.getPointX() - buttonRadius),
                (float) ((double)buttonCenter.getPointY() - buttonRadius),
                (float) ((double)buttonCenter.getPointX() + buttonRadius),
                (float) ((double)buttonCenter.getPointY() + buttonRadius));
        this.buttonFillOval = buttonFillOval;
    }

    /**
     * create the button Bitmap
     *
     * @return 需要绘制到按钮上的PixelMap
     */
    PixelMap createButtonShadowBitmap() {
        int shadowRadius = (int) buttonElevation * 2;
        int bitmapRadius = buttonRadius + (shadowRadius / 2);
        int bitmapSize = bitmapRadius * 2;
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        options.size = new ohos.media.image.common.Size(bitmapSize, bitmapSize);
        options.pixelFormat = PixelFormat.ARGB_8888;
        options.editable = true;
        PixelMap shadowBitmap = PixelMap.create(options);//Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888);
        shadowBitmap.writePixels(0x0);//writePixels(0x0); //writePixels

        Color colors[] = {
                new Color(ColorUtils.setAlphaComponent(SHADOW_COLOR, SHADOW_ALPHA)),
                new Color(ColorUtils.setAlphaComponent(SHADOW_COLOR, 0))
        };

        float stops[] = {
                (float) (buttonRadius - (shadowRadius / 2)) / (float) bitmapRadius,
                1f
        };

        Paint paint = new Paint();
        paint.setAntiAlias(true);  //RadialGradient 圆形波纹效果
        RadialShader radialShader = new RadialShader(new Point(bitmapRadius, bitmapRadius), ((float) bitmapRadius), stops, colors, Shader.TileMode.CLAMP_TILEMODE);
        paint.setShader(radialShader, Paint.ShaderType.PIXELMAP_SHADER);//new RadialGradient(bitmapRadius, bitmapRadius, bitmapRadius, colors, stops, Shader.TileMode.CLAMP));//setShader
//		paint.setShader(new RadialGradient(bitmapRadius, bitmapRadius, bitmapRadius, colors, stops, Shader.TileMode.CLAMP));
//		canvas.drawRect(0, 0, bitmapSize, bitmapSize, paint);

        return shadowBitmap;
    }

    /**
     * dp to px
     *
     * @param dp
     * @return px
     */
    double dp2px(double dp) {
        return DensityUtil.dip2px(getContext(), dp);
    }


    /**
     * attach MenuOverlayView
     */
    ComponentContainer rootView;//根view
    int translatex = 0;
    int translatey = 0;

    void attachMenuOverlayView() {
        if (menuOverlayView == null) {
            menuOverlayView = new MenuOverlayView(getContext(), this);
            RectFloat start = menuOverlayView.lists.get(0).frame;
            RectFloat end = menuOverlayView.lists.get(menuOverlayView.lists.size() - 1).frame;

            menuOverlayView.setWidth((int) ((double)end.right - (double)start.left) + itemMargin + ((itemMargin != 0) ? 10 : 0));
            menuOverlayView.setHeight((int) ((double)end.bottom - (double)start.top) + itemMargin + ((itemMargin != 0) ? 10 : 0));

        }

        rootView = (ComponentContainer) getComponentParent();
        if (!getRootView(rootView)) {
            rootView = (ComponentContainer) rootView.getComponentParent();
            if (!getRootView(rootView)) {
                rootView = (ComponentContainer) rootView.getComponentParent();
                if (!getRootView(rootView)) {
                    rootView = (ComponentContainer) rootView.getComponentParent();
                }
            }
        }

        DependentLayout.LayoutConfig layoutConfig = new DependentLayout.LayoutConfig();
        layoutConfig.width = DependentLayout.LayoutConfig.MATCH_CONTENT;
        layoutConfig.height = DependentLayout.LayoutConfig.MATCH_CONTENT;
        layoutConfig.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);

        if (!menuOverlayViewAttached) {
            if (rootView.getChildCount() == 6) {
                rootView.removeComponentAt(5);
                for (int i = 0; i < rootView.getChildCount(); i++) {
                    if (rootView.getComponentAt(i).getVisibility() == INVISIBLE) {
                        rootView.getComponentAt(i).setVisibility(VISIBLE);
                        rootView.getComponentAt(i).invalidate();
                    }
                }
            }
            rootView.addComponent(menuOverlayView);
            rootView.moveChildToFront(menuOverlayView);
            menuOverlayView.setVisibility(HIDE);
            setRootbackground(rootView, true);
            menuOverlayViewAttached = true;
        }
        if (menuOverlayView.isPoart()) {
            if (menuPosition.equals("bottom")) {
                menuOverlayView.setTranslation(getComponentPosition().left - 300, getComponentPosition().bottom + 30);
            } else {
                if (menuOverlayView.getComponentPosition().left < 100) {
                    if (list.size() > 12) {
                        menuOverlayView.setTranslationX(80);
                        translatex = 80;
                    }
                    menuOverlayView.setTranslationY(PxUtil.screenHeight() / 2 - menuOverlayView.getHeight() - getHeight() / 2 - 10);
                    translatey = PxUtil.screenHeight() / 2 - menuOverlayView.getHeight() - getHeight() / 2 - 10;
                }
            }
        } else {
            if (menuPosition.equals("bottom")) {
                int ymargin = (list.size() > 5) ? 400 : 200;
                menuOverlayView.setTranslation(getComponentPosition().left - 300, getComponentPosition().bottom - ymargin);
            } else {
                if (menuOverlayView.getComponentPosition().left < 100) {
                    translatex = PxUtil.screenWidth() / 2 - menuOverlayView.getWidth() / 2;
                    menuOverlayView.setTranslationX(translatex);
                }
            }
        }
    }

    private void setRootbackground(Component component, boolean show) {
        if (show) {
            ShapeElement shapeElement = new ShapeElement();
            shapeElement.setRgbColor(new RgbColor(155, 155, 155));
            component.setBackground(shapeElement);
            this.setVisibility(INVISIBLE);
        } else {
            ShapeElement shapeElement = new ShapeElement();
            shapeElement.setRgbColor(new RgbColor(249, 249, 249));
            component.setBackground(shapeElement);
            this.setVisibility(VISIBLE);
            invalidate();
        }
    }


    /**
     * Get the root View form componentContainer
     *
     * @param componentContainer the componentContainer root view
     * @return whether the componentContainer has root view
     */
    private boolean getRootView(ComponentContainer componentContainer) {
        boolean parent = false;
        ComponentContainer parentComponent = componentContainer;

        if (parentComponent.getComponentParent() instanceof DirectionalLayout) {
            System.out.println("gongmengfeiAa" + "DirectionalLayout");
            getRootView((ComponentContainer) parentComponent.getComponentParent());
            parent = false;
        } else if (parentComponent.getComponentParent() instanceof StackLayout) {
            System.out.println("gongmengfeiAa" + "StackLayout");
            getRootView((ComponentContainer) parentComponent.getComponentParent());
            parent = false;
        } else if (parentComponent.getComponentParent() instanceof DependentLayout) {
            System.out.println("gongmengfeiAa" + "DependentLayout");
            getRootView((ComponentContainer) parentComponent.getComponentParent());
            parent = false;
        } else if (parentComponent.getComponentParent() instanceof TableLayout) {
            System.out.println("gongmengfeiAa" + "TableLayout");
            getRootView((ComponentContainer) parentComponent.getComponentParent());
            parent = false;
        } else if (parentComponent.getComponentParent() instanceof PositionLayout) {
            System.out.println("gongmengfeiAa" + "PositionLayout");
            getRootView((ComponentContainer) parentComponent.getComponentParent());
            parent = false;
        } else if (parentComponent.getComponentParent() instanceof AdaptiveBoxLayout) {
            System.out.println("gongmengfeiAa" + "AdaptiveBoxLayout");
            getRootView((ComponentContainer) parentComponent.getComponentParent());
            parent = false;
        } else if (parentComponent.getComponentParent() instanceof ScrollView) {
            System.out.println("gongmengfeiAa" + "ScrollView");
            getRootView((ComponentContainer) parentComponent.getComponentParent());
            parent = false;
        } else {
            System.out.println("gongmengfeiAa" + "isParent");
            parent = true;
            return parent;
        }

        return parent;
    }

    /**
     * 移除显示的menu
     */
    public void detachMenuOverlayView() {
        if (menuOverlayView != null) {// && menuOverlayViewAttached) {
            startShow = false;

		/*	if (menuAnimator != null) {
				menuAnimator.cancel();
				menuAnimator.setDuration(100);
				menuAnimator.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
				menuAnimator.setValueUpdateListener(this);
				menuAnimator.start();
			}*/

            getContext().getUITaskDispatcher().delayDispatch(new Runnable() {
                @Override
                public void run() {
                    if (null != rootView && null != menuOverlayView) {
                        menuOverlayView.setVisibility(HIDE);
                        setRootbackground(rootView, false);
                        rootView.removeComponent(menuOverlayView);
                        menuOverlayView = null;
                        menuOverlayViewAttached = false;
                    }
                }
            }, 200);

        }
    }

    /**
     * parse the menuAnchor
     *
     * @param spec 显示位置
     * @throws IllegalArgumentException Unrecognized FlyoutMenuView menuAnchor
     */
    void parseMenuAnchorSpec(String spec) {

//			one token:
//			top | (right,end) | bottom | (left,start) | center
//
//			two tokens:
//			[ [m] ] center
//			[[m]b]  (inner_start,inner_left,inner_top)
//			[m][b]  (outer_start,outer_left,outer_top)
//			[b[m]]  (inner_end,inner_right,inner_bottom)
//			[b][m]  (outer_end,outer_right,outer_bottom)

        if (!TextTool.isNullOrEmpty(spec)) {
            spec = spec.toLowerCase().trim();
            String[] tokens = spec.split("\\|", 2);

            if (tokens.length == 1) {

                //if there's only one token, then use the convenience anchor matches
                switch (tokens[0]) {
                    case "top":
                        setHorizontalMenuAnchor(0.5f);
                        setHorizontalMenuAnchorOutside(false);
                        setVerticalMenuAnchor(0);
                        setVerticalMenuAnchorOutside(true);
                        break;

                    case "right":
                    case "end":
                        setHorizontalMenuAnchor(1);
                        setHorizontalMenuAnchorOutside(true);
                        setVerticalMenuAnchor(0.5f);
                        setVerticalMenuAnchorOutside(false);
                        break;

                    case "bottom":
                        setHorizontalMenuAnchor(0.5f);
                        setHorizontalMenuAnchorOutside(false);
                        setVerticalMenuAnchor(1);
                        setVerticalMenuAnchorOutside(true);
                        break;

                    case "left":
                    case "start":
                        setHorizontalMenuAnchor(0);
                        setHorizontalMenuAnchorOutside(true);
                        setVerticalMenuAnchor(0.5f);
                        setVerticalMenuAnchorOutside(false);
                        break;

                    case "center":
                        setHorizontalMenuAnchor(0.5f);
                        setHorizontalMenuAnchorOutside(false);
                        setVerticalMenuAnchor(0.5f);
                        setVerticalMenuAnchorOutside(false);
                        break;

                    default:
                        throw new IllegalArgumentException("Unrecognized FlyoutMenuView menuAnchor token \"" + tokens[0] + "\"");
                }

            } else if (tokens.length == 2) {
                // two tokens - parse the horizontal spec, then vertical
                parseMenuAnchorAttachmentSpec(tokens[0], true);
                parseMenuAnchorAttachmentSpec(tokens[1], false);
            }
        }
    }

    void parseMenuAnchorAttachmentSpec(String attachmentSpec, boolean horizontal) {

        float anchor;
        boolean outside;

        switch (attachmentSpec) {
            case "center":
                anchor = 0.5f;
                outside = false;
                break;

            case "inner_start":
            case "inner_left":
            case "inner_top":
                anchor = 0;
                outside = false;
                break;

            case "outer_start":
            case "outer_left":
            case "outer_top":
            case "start":
            case "left":
            case "top":
                anchor = 0;
                outside = true;
                break;

            case "outer_end":
            case "outer_right":
            case "outer_bottom":
            case "end":
            case "right":
            case "bottom":
                anchor = 1;
                outside = true;
                break;

            case "inner_end":
            case "inner_right":
            case "inner_bottom":
                anchor = 1;
                outside = false;
                break;

            default:
                throw new IllegalArgumentException("Unrecognized FlyoutMenuView menuAnchor token \"" + attachmentSpec + "\"");
        }

        if (horizontal) {
            setHorizontalMenuAnchor(anchor);
            setHorizontalMenuAnchorOutside(outside);
        } else {
            setVerticalMenuAnchor(anchor);
            setVerticalMenuAnchorOutside(outside);
        }
    }

    public static class MenuItem {

        int id;

        public MenuItem(Context context, int id) {
            this.id = id;

        }

        public int getId() {
            return id;
        }

        /**
         * Draw the contents of the MenuItem
         *
         * @param canvas         the canvas to draw with
         * @param bounds         the bounds of this item in its coordinate space, where the origin (top,left) is 0,0
         * @param degreeSelected the degree to which this item is selected, will be 0 or 1, and in between during selection animations
         */
        public void onDraw(Canvas canvas, RectFloat bounds, float degreeSelected) {
        }

    }

    private static class MenuItemLayout {
        MenuItem item;
        RectFloat frame;
    }

    class MenuOverlayView extends Component implements DrawTask, TouchEventListener {
        List<MenuItemLayout> lists = new ArrayList<>();  //MenuItemLayout
        FlyoutMenuView flyoutMenuView;

        public MenuOverlayView(Context context, FlyoutMenuView flyoutMenuView) {
            super(context);
            this.flyoutMenuView = flyoutMenuView;
            initView();
        }

        public MenuOverlayView(Context context, AttrSet attrSet) {
            super(context, attrSet);
            initView();
        }

        public MenuOverlayView(Context context, AttrSet attrSet, String styleName) {
            super(context, attrSet, styleName);
            initView();
        }

        public MenuOverlayView(Context context, AttrSet attrSet, int resId) {
            super(context, attrSet);
            initView();
        }


        /**
         * 初始化MenuOverlayView
         */
        void initView() {
            addDrawTask(this);
            setTouchEventListener(this::onTouchEvent);
        }

        @Override
        public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
            compact.correctY(touchEvent);
            switch (touchEvent.getAction()) {
                case TouchEvent.PRIMARY_POINT_DOWN:
                    if (findMenuItemAtLocalPosition(touchEvent.getPointerPosition(touchEvent.getIndex()).getX(), touchEvent.getPointerPosition(touchEvent.getIndex()).getY()) != null) {
                        setSelectedMenuItem(findMenuItemAtLocalPosition(touchEvent.getPointerPosition(touchEvent.getIndex()).getX(), touchEvent.getPointerPosition(touchEvent.getIndex()).getY()));
                        flyoutMenuView.detachMenuOverlayView();
                        return true;
                    } else {
                        flyoutMenuView.detachMenuOverlayView();
                        return true;
                    }
            }
            return false;
        }

        /**
         * 根据点击的位置计算出选中的MenuItem
         *
         * @param x 点击的X轴
         * @param y 点击的Y轴
         * @return 选中的MenuItem
         */
        public MenuItem findMenuItemAtLocalPosition(float x, float y) {
            for (MenuItemLayout menuItemLayout : lists) {
                if (x >= menuItemLayout.frame.left && x <= menuItemLayout.frame.right &&
                        y >= menuItemLayout.frame.top && y <= menuItemLayout.frame.bottom) {
                    return menuItemLayout.item;
                }
            }
            return null;
        }

        @Override
        public void addDrawTask(DrawTask task) {
            super.addDrawTask(task);
            onDraw(this, mCanvasForTaskOverContent);
        }

        /**
         * 计算出MenuItem的相关属性
         */
        private void computeMenuItemPosition() {
            for (int i = 0; i < list.size(); i++) {
                MenuItemLayout itemLayout = new MenuItemLayout();
                itemLayout.item = list.get(i);
                itemLayout.frame = flyoutMenuView.layout.getLayoutRectForItem(i, itemWidth, itemHeight, itemMargin);//new RectFloat(100 + (i%2 == 0?0:150), 100 + (i/2 * 150),200 + (i%2 == 0?0:150),200 + (i/2 * 150));
                lists.add(itemLayout);
            }
        }


        private boolean isPoart() {
            if (PxUtil.screenHeight() > PxUtil.screenWidth()) {
                return true;
            } else {
                return false;
            }
        }

        @Override
        public void onDraw(Component component, Canvas canvas) {
            computeMenuItemPosition();
            Path menuFillOvalPath = new Path();
            double radius = (getHeight()) * Math.abs(startShow ? testProgress : Math.abs(testProgress - 1));
            RectFloat menuFillOval = new RectFloat();
            if (flyoutMenuView.menuPosition.equals("bottom")) {
                menuFillOval.left = (float) ((double)(lists.get(1).frame.left) - radius);
                menuFillOval.top = (float) ((double)(lists.get(1).frame.top) - radius);
                menuFillOval.right = (float) ((double)(lists.get(1).frame.right) + radius);
                menuFillOval.bottom = (float) ((double)(lists.get(1).frame.bottom) + radius);
            } else {
                radius = getWidth() * Math.abs(startShow ? testProgress : Math.abs(testProgress - 1)) * 2;
                int middle = lists.size() - (((GridLayout) flyoutMenuView.layout).cols) / 2;
                menuFillOval.left = (float) ((double)(lists.get(middle).frame.left) - radius);//;
                menuFillOval.top = (float) ((double)(lists.get(middle).frame.top) - radius);
                menuFillOval.right = (float) ((double)(lists.get(middle).frame.right) + radius);
                menuFillOval.bottom = (float) ((double)(lists.get(middle).frame.bottom) + radius);
            }

            menuFillOvalPath.reset();
            menuFillOvalPath.addOval(menuFillOval, Path.Direction.CLOCK_WISE);
            canvas.clipPath(menuFillOvalPath, Canvas.ClipOp.INTERSECT);
            paint.setColor(new Color(0xFFFEFEFE));
            canvas.drawPath(menuFillOvalPath, paint);
            canvas.restore();
            if (flyoutMenuView.buttonColor.equals(selectedItemBackgroundColor + "")) {
                paint.setColor(Color.GRAY);
            } else {
                paint.setColor(new Color(0x66FF4081));
            }
            canvas.save();
            if (startShow) {
                if (null != getSelectedMenuItem() && null != lists.get(getSelectedMenuItem().id)) {
                    canvas.drawRoundRect(lists.get(getSelectedMenuItem().id).frame, 15, 15, paint);
                }
                for (int i = 0; i < lists.size(); i++) {
                    lists.get(i).item.onDraw(canvas, lists.get(i).frame, i);
                }
            }
            canvas.restore();
        }

    }
}
